package com.itcast.netty.handler.listener;

import com.itcast.netty.config.NettyProperties;
import com.itcast.netty.constants.NettyConstants;
import com.itcast.netty.handler.adapter.ServerChannelHandlerAdapter;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * 服务启动监听器
 *
 * @author zheng.zhang
 */
@Slf4j
@Component
public class NettyServerListener {
    /**
     * 创建Bootstrap
     */
    private final ServerBootstrap bootstrap = new ServerBootstrap();

    /**
     * Boss
     */
    private final EventLoopGroup bossGroup = new NioEventLoopGroup();

    /**
     * Worker
     */
    private final EventLoopGroup workerGroup = new NioEventLoopGroup();

    /**
     * 通道适配器
     */
    @Autowired
    private ServerChannelHandlerAdapter handlerAdapter;

    @Autowired
    private NettyProperties nettyConfig;
    /**
     * 开启服务及线程
     */
    public void start() {
        // 从配置文件中获取端口号
        int port = nettyConfig.getPort() == null ? 9999 : nettyConfig.getPort();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128)
                .handler(new LoggingHandler(LogLevel.INFO));
        try {
            // 设置事件处理
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    pipeline.addLast(new LengthFieldBasedFrameDecoder(NettyConstants.MAX_FRAME_LENGTH, 0, 2, 0, 2));
                    pipeline.addLast(new LengthFieldPrepender(2));
                    pipeline.addLast(handlerAdapter);
                }
            });
            log.info("Netty 服务器在[{}]端口启动监听", port);
            // 绑定端口,同步等待资源
            ChannelFuture channelFuture = bootstrap.bind(port).sync();
            // 等待服务器监听端口关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("Netty 服务器启动失败: {}", e.getMessage());
        } finally {
            log.info("释放资源");
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    /**
     * 关闭服务器方法
     */
    @PreDestroy
    public void close() {
        log.info("<======关闭服务器中========>");
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }
}
